#pragma once
///mysql版本
/******************************************************************************************
 * mode:主要用来和数据提供交互，对外提供访问数据的接口
 * 该模块为连接存放题目的数据库，并且从数据库中获得题目信息
 * 主要逻辑:
 * 1.利用connect/C库连接本地的数据库，并且利用sql语句获得对应的题目信息
 * 2.提供读取所有题目以及特定题目的接口
 *******************************************************************************************/
#include "../Comm/comm.hpp"
#include "../Comm/log.hpp"
#include "../Comm/util.hpp"
#include "include/mysql.h"

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;
    const std::string table_name = "oj_questions";                // 数据库中保存题目的表的名称
    const std::string host = "127.0.0.1";
    const std::string user = "oj_client";
    const std::string passwd = "123456";
    const std::string db = "oj";
    const unsigned int port = 3306;

    // 此类的功能为题目的描述
    struct Question
    {
        std::string _number; // 题目的编号，唯一
        std::string _title;  // 题目的标题
        std::string _star;   // 题目的难度
        int _cpu_limit;      // 时间约束
        int _mem_limit;      // 空间约束
        std::string _desc;   // 题目的描述
        std::string _header; // 题目的预设代码
        std::string _tail;   // 题目的测试用例，与header拼接在一起使用
    };
    // 此类的功能为建立题目序号与题目内容的映射关系，并提供对题目的操纵接口
    class Model
    {
        private:
            //题号和题目细节的映射
            std::unordered_map<std::string,Question> _questions;
        public:
            Model(){}
            ~Model(){}
            //此函数为与数据库进行命令交互
            bool QueryMySql(const std::string& sql,std::vector<Question> *out)
            { 
                //初始化mysql,创建文件句柄
                MYSQL *mysql = mysql_init(nullptr);

                //连接数据库
                if(nullptr == mysql_real_connect(mysql,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0))
                {
                    //连接失败
                    LOG(FATAL)<<"数据库连接失败！"<<"\n";
                    return false;
                }

                //设置编码格式为utf8
                mysql_set_character_set(mysql,"utf8");

                //执行sql语句
                if(0!=mysql_query(mysql,sql.c_str()))
                {
                    LOG(WARNING)<<sql<<" execute error!"<<"\n";
                    return false;
                }
                //执行成功，获取结果
                MYSQL_RES * res = mysql_store_result(mysql);

                //获取行数和列数
                int rows = mysql_num_rows(res);
                int clos = mysql_num_fields(res);

                Question qus;
                for(int i =0;i<rows;i++)
                {
                    MYSQL_ROW row = mysql_fetch_row(res);//提取一行的内容
                    qus._number = row[0];
                    qus._title = row[1];
                    qus._star = row[2];
                    qus._desc = row[3];
                    qus._header = row[4];
                    qus._tail = row[5];
                    qus._cpu_limit = atoi(row[6]);
                    qus._mem_limit = atoi(row[7]);
                    out->push_back(qus);
                }
                free(res);
                mysql_close(mysql);
                return true;

            }
            
            //此函数功能获取所有题目
            bool GetAllQuestion(std::vector<Question> *out)
            {
               std::string sql = "select * from ";
               sql+= table_name;
               return QueryMySql(sql,out);
            }
            //此函数功能为获取单个指定题目
            bool GetOneQuestion(const std::string& number,Question *q)//输入的为题目的序号
            {
                bool res = false;
                std::string sql = "select * from ";
                sql+= table_name;
                sql+= " where number=";
                sql+= number;
                std::vector<Question> result;
                //访问一个题目必然返回一条结果或者不返回
                if(QueryMySql(sql,&result))
                {
                    if(result.size()==1)
                    {
                        *q = result[0];
                        res = true;
                    }
                }
                return res;
            }
    };
}
